package com.generated;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * 数据库反向生成
 * Created by zhu on 2017/5/26.
 */
public class GeneratedMain {
    private String pojoOutPath = "com.zhu.gen.entity";//指定实体生成路径
    private String mapperOutPath = "com.zhu.gen.mapper";//指定mapper文件生成路径
    private String xmlOutPath = "com.zhu.gen.mapper";//指定xml文件生成路径
    private String authorName = "zhu";//作者名字
    List<TableBO> boList = new ArrayList<TableBO>();
    //数据暂存至boList
    private void saveList(List<List> list){
        String temp = "";
        //数据库,表,列,列类型,注释
        System.out.println("数据库:"+list.get(0).get(0));
        List<TableBO.Columns> cList = null;
        for (List obj : list){
            TableBO.Columns columns = new TableBO().new Columns();
            //表名不等
            if (!temp.equalsIgnoreCase(obj.get(1).toString())){
                //!=null 初次循环排外
                if (cList != null){
                    TableBO bo = new TableBO();
                    bo.setTableName(temp);
                    bo.setColumnsList(cList);
                    boList.add(bo);
                }
                //初始化
                cList = new ArrayList<TableBO.Columns>();
                temp = obj.get(1).toString();

            }
            columns.setColumn(obj.get(2).toString());
            columns.setColumnType(obj.get(3).toString());
            columns.setColumnAnno(obj.get(4).toString());
            cList.add(columns);
        }
        //最后一个表
        if (boList != null){
            TableBO bo = new TableBO();
            bo.setTableName(temp);
            bo.setColumnsList(cList);
            boList.add(bo);
        }
    }
    //格式化大小写
    private String formatCap(String str , boolean headformat){
        String[] strs = str.split("_");
        StringBuffer sb = new StringBuffer();
        for (int i = 0 ; i < strs.length ; i++){
            String ss = strs[i].toLowerCase();
            if (!headformat && i == 0){
                sb.append(ss);
            }else {
                sb.append(initcap(ss));
            }
        }
        return sb.toString().replace("_","");
    }
    //首字母大写转换
    private String initcap(String str) {
        str = str.toLowerCase();//先转换为小写
        char[] ch = str.toCharArray();
        if(ch[0] >= 'a' && ch[0] <= 'z'){
            ch[0] = (char)(ch[0] - 32);
        }
        return new String(ch);
    }
    //-----------------POJO部分 start
    //生成实体类主体代码
    private String parse(TableBO bo) {
        StringBuffer sb = new StringBuffer();
        sb.append("package " + this.pojoOutPath + ";\r\n");
        //判断是否导入工具包
        for(TableBO.Columns c:bo.getColumnsList()){
            if(c.getColumnType().equalsIgnoreCase("date") || c.getColumnType().equalsIgnoreCase("datetime")){
                sb.append("import java.util.Date;\r\n");
                break;
            }
        }
        //注释部分
        sb.append("/**\r\n");
        sb.append(" * "+bo.getTableName()+" 实体类\r\n");
        sb.append(" * "+new Date()+" "+this.authorName+"\r\n");
        sb.append(" */ \r\n");
        //实体部分
        sb.append("public class " + formatCap(bo.getTableName(),true) + "{\r\n");
        processAllAttrs(sb,bo);//属性
        processAllMethod(sb,bo);//get set方法
        sb.append("}\r\n");
        return sb.toString();
    }
    //生成get set 方法
    private void processAllMethod(StringBuffer sb, TableBO bo) {
        for(TableBO.Columns c : bo.getColumnsList()){
            sb.append("\tpublic void set" + formatCap(c.getColumn(),true) + "(" + converType(c.getColumnType()) + " " +
                    formatCap(c.getColumn(),false) + "){\r\n");
            sb.append("\tthis." + formatCap(c.getColumn(),false) + "=" + formatCap(c.getColumn(),false) + ";\r\n");
            sb.append("\t}\r\n");
            sb.append("\tpublic " + converType(c.getColumnType()) + " get" + formatCap(c.getColumn(),true) + "(){\r\n");
            sb.append("\t\treturn " + formatCap(c.getColumn(),false) + ";\r\n");
            sb.append("\t}\r\n");
        }


    }
    //数据库 > java POJO数据类型转换
    private String converType(String columnType) {
        if(columnType.equalsIgnoreCase("bit")){
            return "boolean";
        }else if(columnType.equalsIgnoreCase("tinyint")){
            return "byte";
        }else if(columnType.equalsIgnoreCase("smallint")){
            return "short";
        }else if(columnType.equalsIgnoreCase("int")){
            return "Integer";
        }else if(columnType.equalsIgnoreCase("bigint")){
            return "long";
        }else if(columnType.equalsIgnoreCase("float")){
            return "float";
        }else if(columnType.equalsIgnoreCase("decimal") || columnType.equalsIgnoreCase("numeric")
                || columnType.equalsIgnoreCase("real") || columnType.equalsIgnoreCase("money")
                || columnType.equalsIgnoreCase("smallmoney")){
            return "double";
        }else if(columnType.equalsIgnoreCase("varchar") || columnType.equalsIgnoreCase("char")
                || columnType.equalsIgnoreCase("nvarchar") || columnType.equalsIgnoreCase("nchar")
                || columnType.equalsIgnoreCase("text")){
            return "String";
        }else if(columnType.equalsIgnoreCase("datetime")){
            return "Date";
        }else if(columnType.equalsIgnoreCase("image")){
            return "Blod";
        }
        return "Object";
    }
    //字段生成
    private void processAllAttrs(StringBuffer sb, TableBO bo) {
        for(TableBO.Columns c : bo.getColumnsList()){
            sb.append("   /**\r\n");
            sb.append("    * "+c.getColumnAnno()+"\r\n");
            sb.append("    */ \r\n");
            sb.append("\tprivate "+ converType(c.getColumnType()) +" "+ formatCap(c.getColumn(),false) + ";\r\n");
        }
    }
    //创建文件
    private void createJava()  {
        System.out.println("正在生成实体类。。");
        for (TableBO bo : boList){
                File directory = new File("");
                String outputPath = directory.getAbsolutePath()+ "/target/generated-sources/"+this.pojoOutPath.replace(".", "/");
                File temp = new File(outputPath);
                if (!temp.exists()){
                    temp.mkdirs();
                }
            FileWriter fw = null;
            try {
                String path = outputPath+"/"+formatCap(bo.getTableName(),true) + ".java";
                System.out.println(path);
                fw = new FileWriter(path);
            } catch (IOException e) {
                e.printStackTrace();
            }
            PrintWriter pw = new PrintWriter(fw);
            pw.println(parse(bo));
            pw.flush();
            pw.close();
            System.out.println("实体类 "+formatCap(bo.getTableName(),true)+"生成成功!");
        }
        System.out.println("实体类生成完毕!");

    }
    //-----------------POJO部分 end
    //-----------------Mapper部分 start
    //生成主体代码
    private String parseMapper(TableBO bo){
        StringBuffer sb = new StringBuffer();
        sb.append("package " + this.mapperOutPath + ";\r\n");
        sb.append("import " + this.pojoOutPath + "."+formatCap(bo.getTableName(),true)+";\n");
        sb.append("import java.util.List;\n" );
        //注释部分
        sb.append("/**\r\n");
        sb.append(" * "+bo.getTableName()+" Mapper类\r\n");
        sb.append(" * "+new Date()+" "+this.authorName+"\r\n");
        sb.append(" */ \r\n");
        //方法部分
        sb.append("public interface " + formatCap(bo.getTableName(),true) + "Mapper{");
        sb.append("\r\n\r\n");
        sb.append("\t"+formatCap(bo.getTableName(),true)+" findOne("+converType(bo.getColumnsList().get(0).getColumnType())+" "+formatCap(bo.getColumnsList().get(0).getColumn(),false)+");");
        sb.append("\r\n\r\n");
        sb.append("\tList<"+formatCap(bo.getTableName(),true)+"> find(Object param);");
        sb.append("\r\n\r\n");
        sb.append("\tvoid deleteOne("+converType(bo.getColumnsList().get(0).getColumnType())+" "+formatCap(bo.getColumnsList().get(0).getColumn(),false)+");");
        sb.append("\r\n\r\n");
        sb.append("\tvoid delete("+formatCap(bo.getTableName(),true)+" param);");
        sb.append("\r\n\r\n");
        sb.append("\tvoid insert("+formatCap(bo.getTableName(),true)+" param);");
        sb.append("\r\n\r\n");
        sb.append("\tvoid update("+formatCap(bo.getTableName(),true)+" param);");
        sb.append("\r\n\r\n");
        sb.append("\tvoid updateWithAllFields("+formatCap(bo.getTableName(),true)+" param);");
        sb.append("\r\n\r\n");
        sb.append("}\r\n");
        return sb.toString();
    }
    //创建文件
    private void createMapper() {
        for (TableBO bo : boList){
            File directory = new File("");
            String outputPath = directory.getAbsolutePath()+ "/target/generated-sources/"+this.mapperOutPath.replace(".", "/");
            File temp = new File(outputPath);
            if (!temp.exists()){
                temp.mkdirs();
            }
            FileWriter fw = null;
            try {
                String path = outputPath+"/"+formatCap(bo.getTableName(),true) + "Mapper.java";
                System.out.println(path);
                fw = new FileWriter(path);
            } catch (IOException e) {
                e.printStackTrace();
            }
            PrintWriter pw = new PrintWriter(fw);
            pw.println(parseMapper(bo));
            pw.flush();
            pw.close();
            System.out.println("mapper "+formatCap(bo.getTableName(),true)+"生成成功!");
        }
        System.out.println("mapper生成完毕!");
    }
    //-----------------Mapper部分 end
    //-----------------Mapperxml部分 start
    //生成主体代码
    private String parseMapperXml(TableBO bo){
        StringBuffer sb = new StringBuffer();
        sb.append("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n" +
                "<!DOCTYPE mapper\n" +
                "        PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\"\n" +
                "        \"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">\n\n");
        sb.append(" <mapper namespace=\""+mapperOutPath+"."+formatCap(bo.getTableName(),true)+"Mapper\">\n");
        //方法部分
        createMapperXmlFindOne(sb,bo);
        createMapperXmlFind(sb, bo);
        createMapperXmlDeleteOne(sb, bo);
        createMapperXmlDelete(sb, bo);
        createMapperXmlInsert(sb, bo);
        createMapperXmlUpdate(sb, bo);
        createMapperXmlUpdateWithAllFields(sb, bo);

        sb.append("</mapper>");
        return sb.toString();
    }
    private void createMapperXmlUpdateWithAllFields(StringBuffer sb, TableBO table) {
        sb.append("\t<update id=\"updateWithAllFields\" parameterType=\""+pojoOutPath+"."+formatCap(table.getTableName(),true)+"\">\n" +
                "\t\tupdate\n" +
                "\t\t\t"+table.getTableName()+" t\n" +
                "\t\tset \n" );
        for (TableBO.Columns c : table.getColumnsList()){
            sb.append("\t\t\tt."+c.getColumn()+" = #{"+formatCap(c.getColumn(),false)+"},\n");
        }
        sb.replace(sb.lastIndexOf(","), sb.lastIndexOf(",") + 1, "");
        sb.append("\n\t\twhere\n");
        sb.append("\t\t\tt."+table.getColumnsList().get(0).getColumn()+" = #{"+formatCap(table.getColumnsList().get(0).getColumn(),false)+"}\n");
        sb.append("\t</update>\n");

    }
    private void createMapperXmlUpdate(StringBuffer sb, TableBO table) {
        sb.append("\t<update id=\"update\" parameterType=\""+pojoOutPath+"."+formatCap(table.getTableName(),true)+"\">\n" +
                "\t\tUPDATE \n" +
                "\t\t\t"+table.getTableName()+" t\n" +
                "\t\t<set>\n" );
        for (TableBO.Columns c : table.getColumnsList()){
            sb.append("\t\t\t<if test=\""+formatCap(c.getColumn(),false)+" != null \">\n" +
                    "\t\t\t\t\t\t t."+c.getColumn()+" = #{"+formatCap(c.getColumn(),false)+"},\n" +
                    "\t\t\t</if>\n");
        }
        sb.replace(sb.lastIndexOf(","), sb.lastIndexOf(",") + 1, "");
        sb.append("\t\t</set>\n" +
                "\t\tWHERE\n" +
                "\t\t\tt."+table.getColumnsList().get(0).getColumn()+" = #{"+formatCap(table.getColumnsList().get(0).getColumn(),false)+"}\n"+
                "\t</update>\n");
    }
    private void createMapperXmlInsert(StringBuffer sb, TableBO table) {
            sb.append("\t<insert id=\"insert\" parameterType=\""+pojoOutPath+"."+formatCap(table.getTableName(),true)+"\">\n" +
                    "\t\tINSERT INTO\n" +
                    "\t\t\t"+table.getTableName()+"\n" +
                    "\t\t(\n" );
            for (TableBO.Columns c : table.getColumnsList()){
                sb.append("\t\t\t"+c.getColumn()+",\n");
            }
            sb.replace(sb.lastIndexOf(","), sb.lastIndexOf(",") + 1, "");
            sb.append("\n\t\t)\n" +
                    "\t\tVALUES \n" +
                    "\t\t(\n" );
            for (TableBO.Columns c : table.getColumnsList()){
                sb.append("\t\t\t#{"+formatCap(c.getColumn(),false)+"},\n");
            }
            sb.replace(sb.lastIndexOf(","), sb.lastIndexOf(",") + 1, "");
            sb.append("\n\t\t)\n" +
                    "\t</insert>\n");
    }
    private void createMapperXmlDelete(StringBuffer sb, TableBO table) {
        sb.append("\t<delete id=\"delete\" parameterType=\""+pojoOutPath+"."+formatCap(table.getTableName(),true)+"\">\n" +
                "\t\tDELETE FROM\n" +
                "\t\t\t"+table.getTableName()+" \n");
        sb.append("\t\t<where>\n");
        sb.append("\t\t\tdel_flag = 0 \n");
        for (TableBO.Columns c : table.getColumnsList()){
            sb.append("\t\t\t<if test=\""+formatCap(c.getColumn(),false)+" != null \">\n" +
                    "\t\t\t\t\t\tAND "+c.getColumn()+" = #{"+formatCap(c.getColumn(),false)+"}\n" +
                    "\t\t\t</if>\n");
        }
        sb.append("\t\t</where>\n");
        sb.append("\t</delete>\n");
    }
    private void createMapperXmlDeleteOne(StringBuffer sb, TableBO table) {
        sb.append("\t<delete id=\"deleteOne\" parameterType=\""+converType(table.getColumnsList().get(0).getColumnType())+"\">\n" +
                "\t\tDELETE FROM\n" +
                "\t\t\t"+table.getTableName()+"  \n" +
                "\t\tWHERE\n" +
                "\t\t\t"+table.getColumnsList().get(0).getColumn()+" = #{"+formatCap(table.getColumnsList().get(0).getColumn(),false)+"}\n" +
                "\t</delete>\n");
    }
    private void createMapperXmlFindOne(StringBuffer sb, TableBO table) {
        sb.append("\t<select id=\"findOne\" parameterType=\""+converType(table.getColumnsList().get(0).getColumnType())+"\" resultType=\""+pojoOutPath+"."+formatCap(table.getTableName(),true)+"\">\n");
        sb.append("\t\tSELECT\n");
        for(TableBO.Columns c:table.getColumnsList()){
            sb.append("\t\t\tt."+c.getColumn()+" AS " +formatCap(c.getColumn(),false)+ ",\n");
        }
        sb.replace(sb.lastIndexOf(","), sb.lastIndexOf(",") + 1, "");
        sb.append("\t\tFROM "+table.getTableName()+" t\n");
        sb.append("\t\twhere\n");
        sb.append("\t\t\tt."+table.getColumnsList().get(0).getColumn()+" = #{"+formatCap(table.getColumnsList().get(0).getColumn(),false)+"}\n");
        sb.append("\t</select>\n");
    }
    private void createMapperXmlFind(StringBuffer sb, TableBO table) {
        sb.append("\t<select id=\"find\" parameterType=\""+converType(table.getColumnsList().get(0).getColumnType())+"\" resultType=\""+pojoOutPath+"."+formatCap(table.getTableName(),true)+"\">\n");
        sb.append("\t\tSELECT\n");
        for(TableBO.Columns c:table.getColumnsList()){
            sb.append("\t\t\tt."+c.getColumn()+" AS " +formatCap(c.getColumn(),false)+ ",\n");
        }
        sb.replace(sb.lastIndexOf(","), sb.lastIndexOf(",") + 1, "");
        sb.append("\t\tFROM " + table.getTableName() + " t\n");
        sb.append("\t\t<where>\n");
        sb.append("\t\t\tdel_flag = 0 \n");
        createCondition(sb,table.getColumnsList());
        sb.append("\t\t</where>\n");
        sb.append("\t</select>\n");
    }
    private void createCondition(StringBuffer sb, List<TableBO.Columns> columnsList) {
        for (TableBO.Columns c : columnsList){
            sb.append("\t\t\t<if test=\""+formatCap(c.getColumn(),false)+" != null \">\n" +
                     "\t\t\t\t\t\tAND t."+c.getColumn()+" = #{"+formatCap(c.getColumn(),false)+"}\n" +
                     "\t\t\t</if>\n");
        }
    }
    //创建文件
    private void createMapperXml() {
        for (TableBO bo : boList){
            File directory = new File("");
            String outputPath = directory.getAbsolutePath()+ "/target/generated-sources/"+this.xmlOutPath.replace(".", "/");
            File temp = new File(outputPath);
            if (!temp.exists()){
                temp.mkdirs();
            }
            FileWriter fw = null;
            try {
                String path = outputPath+"/"+formatCap(bo.getTableName(),true) + "Mapper.xml";
                System.out.println(path);
                fw = new FileWriter(path);
            } catch (IOException e) {
                e.printStackTrace();
            }
            PrintWriter pw = new PrintWriter(fw);
            pw.println(parseMapperXml(bo));
            pw.flush();
            pw.close();
            System.out.println("xml "+formatCap(bo.getTableName(),true)+"生成成功!");
        }
        System.out.println("xml生成完毕!");
    }
    //-----------------Mapperxml部分 end
    public static void main(String[] args) throws IOException {
        BaseDao baseDao = new BaseDao();
        List<List> list =baseDao.query();
        GeneratedMain t = new GeneratedMain();
        t.saveList(list);
        //创建java实体类
        t.createJava();
        //创建mapper文件
        t.createMapper();
        //创建xml
        t.createMapperXml();
    }
}
